﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace WayPointNavigator
{
    public struct Point : IEquatable<Point>
    {
        public Point(float x, float y, float z) : this()
        {
            X = x;
            Y = y;
            Z = z;
        }

        public Point(XElement xml)
            : this(
                Convert.ToSingle(xml.Attribute("X").Value), Convert.ToSingle(xml.Attribute("Y").Value),
                Convert.ToSingle(xml.Attribute("Z").Value))
        {}

        public float X { get; set; }
        public float Y { get; set; }
        public float Z { get; set; }

        #region IEquatable<Point> Members

        public bool Equals(Point other)
        {
            return other.X == X && other.Y == Y && other.Z == Z;
        }

        #endregion

        public double Distance(Point to)
        {
            return Distance(to.X, to.Y, to.Z);
        }

        public double Distance(float toX, float toY, float toZ)
        {
            float dX = X - toX;
            float dY = Y - toY;
            float dZ = Z - toZ;
            return Math.Sqrt(dX * dX + dY * dY + dZ * dZ);
        }

        public XElement GetXml()
        {
            return new XElement("Point", new XAttribute("X", X), new XAttribute("Y", Y), new XAttribute("Z", Z));
        }

        public CircularQueue<Point> LoadFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("Could not find the specified file!", filePath);
            }

            var ret = new CircularQueue<Point>();
            XElement file = XElement.Load(filePath);
            IEnumerable<XElement> points = from p in file.Descendants("Point")
                                           select p;
            foreach (XElement point in points)
            {
                ret.Enqueue(new Point(point));
            }
            return ret;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }
            if (obj.GetType() != typeof(Point))
            {
                return false;
            }
            return Equals((Point) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = X.GetHashCode();
                result = (result * 397) ^ Y.GetHashCode();
                result = (result * 397) ^ Z.GetHashCode();
                return result;
            }
        }

        public static bool operator ==(Point left, Point right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(Point left, Point right)
        {
            return !left.Equals(right);
        }
    }
}